package jp.tkym.labs.store;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import jp.tkym.labs.store.ormap.OrMapElement;
import jp.tkym.labs.store.ormap.OrMapObject;
import jp.tkym.labs.store.ormap.OrMapObjectProvider;
import jp.tkym.labs.util.beankey.BeanKey;
import jp.tkym.labs.util.beankey.BeanKeyGenerator;

class ManagedBeanCache{
	private Map<Class<?>, Set<BeanKey>> keySets = new ConcurrentHashMap<Class<?>, Set<BeanKey>>();
	private Map<Class<?>, BeanKeyGenerator<?>> keyGenerators = new ConcurrentHashMap<Class<?>, BeanKeyGenerator<?>>();
	
	<T> boolean isManaged(Class<T> cls){
		return keySets.containsKey(cls);
	}	
	
	synchronized <T> void manageForClass(T bean){
		manage(classOf(bean));
	}
	
	synchronized <T> void manage(Class<T> cls){
		keyGenerators.put(cls, new BeanKeyGenerator<T>(cls, idProperties(cls)));
		keySets.put(cls, new HashSet<BeanKey>());
	}
	
	private <T> String[] idProperties(Class<T> cls){
		OrMapObject object = OrMapObjectProvider.getInstance().get(cls);
		List<String> idList = new ArrayList<String>(object.ids().size());
		for(OrMapElement element : object.ids())idList.add(element.getPropertyName());
		String[] idProperties = new String[idList.size()];
		idList.toArray(idProperties);
		return idProperties;
	}
	
	<T> boolean isManagedForClass(T bean) {
		return isManaged(classOf(bean));
	}
	
	<T> boolean isManaged(T bean) {
		Class<T> cls = classOf(bean);
		BeanKeyGenerator<T> keyGenerator = keyGenerator(cls);
		if(keyGenerator == null) return false;
		BeanKey key = keyGenerator.generate(bean);
		return keySets.get(cls).contains(key);
	}
	
	<T> void manage(T bean){
		Class<T> cls = classOf(bean);
		BeanKeyGenerator<T> keyGenerator = keyGenerator(cls);
		if(keyGenerator == null){
			String msg = "Class " + cls.getName()+" is not managed";
			throw new IllegalStateException(msg);
		} 
		BeanKey key = keyGenerator.generate(bean);
		Set<BeanKey> keySet = keySets.get(cls);
		if(!keySet.contains(key)){
			keySet.add(key);
		}
	}
	
	<T> void detach(T bean){
		Class<T> cls = classOf(bean);
		BeanKeyGenerator<T> keyGenerator = keyGenerator(cls);
		if(keyGenerator == null){
			String msg = "Class " + cls.getName()+" is not managed";
			throw new IllegalStateException(msg);
		} 
		BeanKey key = keyGenerator.generate(bean);
		Set<BeanKey> keySet = keySets.get(cls);
		if(keySet.contains(key)){
			keySet.remove(key);
		}
	}

	@SuppressWarnings("unchecked")
	<T> BeanKeyGenerator<T> keyGenerator(Class<T> cls){
		return (BeanKeyGenerator<T>) keyGenerators.get(cls);
	}
	
	@SuppressWarnings("unchecked")
	<T> Class<T> classOf(T bean){
		return (Class<T>)bean.getClass();
	}
}